package cn.sunxiansheng.log4j2.aspectj;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * Description: 使用 AOP 打印带 TraceId 的箭头日志
 *
 * @Author sun
 * @Create 2024/8/2 12:11
 * @Version 1.0
 */
@Aspect
@Component
@Slf4j
@Order(1)
public class TraceIdLoggingAspect {

    // ANSI 颜色代码：绿色和重置格式
    private static final String GREEN = "\u001B[32m";
    private static final String RESET = "\u001B[0m";

    // 箭头的总长度
    private static final int TOTAL_WIDTH = 150;

    // 这里必须使用 @Autowired 注入 Tracer
    @Autowired
    private Tracer tracer;

    // 配置切点，匹配所有 controller 包中的所有方法
    @Pointcut("execution(public * *..controller..*(..))")
    public void controllerMethods() {}

    // 在方法执行前打印带有 TraceId 的箭头日志
    @Before("controllerMethods()")
    public void logRequest() {
        // 使用 Tracer 获取 TraceId
        String traceId = null;
        try {
            traceId = tracer.currentSpan().context().traceId();
        } catch (Exception e) {
            log.warn("traceId 为空！");
        }

        // 生成带有 Trace ID 的箭头字符串
        String arrowWithTraceId = getArrowWithTraceId(traceId);

        // 打印日志
        log.info("\n" + arrowWithTraceId);
    }

    /**
     * 生成三行箭头，并且只有中间的行显示 Trace ID。
     *
     * @param traceId Trace ID
     * @return 带有三行箭头的字符串
     */
    private String getArrowWithTraceId(String traceId) {
        int traceIdLength = traceId.length();

        // 动态计算中间行两侧的箭头长度
        int sideLength = (TOTAL_WIDTH - traceIdLength) / 2;
        String sideArrow = generateArrow(sideLength);

        // 构建三行箭头，只有中间行包含 Trace ID
        String topArrow = generateArrow(TOTAL_WIDTH);
        String middleArrow = sideArrow + traceId + sideArrow;
        String bottomArrow = generateArrow(TOTAL_WIDTH);

        return GREEN + topArrow + "\n" + middleArrow + "\n" + bottomArrow + RESET;
    }

    /**
     * 使用 StringBuilder 生成指定长度的箭头字符串。
     *
     * @param length 箭头的长度
     * @return 包含指定长度箭头的字符串
     */
    private String generateArrow(int length) {
        StringBuilder arrow = new StringBuilder();
        for (int i = 0; i < length; i++) {
            arrow.append('=');
        }
        return arrow.toString();
    }
}
